%option noyywrap
%{
/*****************声明和选项设置  begin*****************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "parse_tree.h"
#include "syntax_analyzer.h"

int lines=1;
int pos_start=1;
int pos_end=1;
char token_name[20];

void new_node(char *text){
     yylval.node = new_parse_tree_node(text);
}

/*****************声明和选项设置  end*****************/
%}

/*标识符*/
digit [0-9]
identifier_nondigit [a-zA-Z_]
identifier {identifier_nondigit}({identifier_nondigit}|{digit})*

/*整型常量*/
hex_digit [0-9a-fA-F]
oct_digit [0-7]
non_digit [1-9]
hex_pre 0[xX]
hex_cons 0[xX]{hex_digit}+
oct_cons 0{oct_digit}*
decimal {non_digit}{digit}*
integer ({decimal}|{oct_cons}|{hex_cons})

/*浮点数*/
hex_digit_seq {hex_digit}+
sign ("+"|"-")
digit_seq {digit}+
bi_expo ("p"|"P"){sign}?{digit_seq}
hex_fra_cons ({hex_digit_seq}?"."{hex_digit_seq}|{hex_digit_seq}".")
expo ("e"|"E"){sign}?{digit_seq}
fra_cons ({digit_seq}?"."{digit_seq}|{digit_seq}".")
hex_floating {hex_pre}({hex_fra_cons}|{hex_digit_seq}){bi_expo}
decimal_floating ({fra_cons}{expo}?|{digit_seq}{expo})
floating ({decimal_floating}|{hex_floating})




%%

[ \t\r]+  ;  // 忽略空格和制表符
\n        { pos_start = 1; pos_end = 1; lines += 1; }

"int"      { pos_start = pos_end; pos_end += 3; strcpy(token_name, "INT"); new_node(yytext); return INT; }
"float"    { pos_start = pos_end; pos_end += 5; strcpy(token_name, "FLOAT"); new_node(yytext); return FLOAT; }
"void"     { pos_start = pos_end; pos_end += 4; strcpy(token_name, "VOID"); new_node(yytext); return VOID; }
"const"    { pos_start = pos_end; pos_end += 5; strcpy(token_name, "CONST"); new_node(yytext); return CONST; }
"return"   { pos_start = pos_end; pos_end += 6; strcpy(token_name, "RETURN"); new_node(yytext); return RETURN; }
"if"       { pos_start = pos_end; pos_end += 2; strcpy(token_name, "IF"); new_node(yytext); return IF; }
"else"     { pos_start = pos_end; pos_end += 4; strcpy(token_name, "ELSE"); new_node(yytext); return ELSE; }
"while"    { pos_start = pos_end; pos_end += 5; strcpy(token_name, "WHILE"); new_node(yytext); return WHILE; }
"break"    { pos_start = pos_end; pos_end += 5; strcpy(token_name, "BREAK"); new_node(yytext); return BREAK; }
"continue" { pos_start = pos_end; pos_end += 8; strcpy(token_name, "CONTINUE"); new_node(yytext); return CONTINUE; }

{identifier} { pos_start = pos_end; pos_end += yyleng; strcpy(token_name, "IDENT"); new_node(yytext); return IDENT; }

{integer}    { pos_start = pos_end; pos_end += yyleng; strcpy(token_name, "INTCONST"); new_node(yytext); return INTCONST; }
{floating} { pos_start = pos_end; pos_end += yyleng; strcpy(token_name, "FLOATCONST"); new_node(yytext); return FLOATCONST; }

"==" { pos_start = pos_end; pos_end += 2; strcpy(token_name, "EQ"); new_node(yytext); return EQ; }
"!=" { pos_start = pos_end; pos_end += 2; strcpy(token_name, "NEQ"); new_node(yytext); return NEQ; }
"<"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "LT"); new_node(yytext); return LT; }
"<=" { pos_start = pos_end; pos_end += 2; strcpy(token_name, "LET"); new_node(yytext); return LET; }
">"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "GT"); new_node(yytext); return GT; }
">=" { pos_start = pos_end; pos_end += 2; strcpy(token_name, "GET"); new_node(yytext); return GET; }

"+"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "ADD"); new_node(yytext); return ADD; }
"-"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "SUB"); new_node(yytext); return SUB; }
"*"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "MUL"); new_node(yytext); return MUL; }
"/"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "DIV"); new_node(yytext); return DIV; }
"%"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "MOD"); new_node(yytext); return MOD; }

"&&" { pos_start = pos_end; pos_end += 2; strcpy(token_name, "AND"); new_node(yytext); return AND; }
"||" { pos_start = pos_end; pos_end += 2; strcpy(token_name, "OR"); new_node(yytext); return OR; }
"!"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "NOT"); new_node(yytext); return NOT; }

";"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "SEMICOLON"); new_node(yytext); return SEMICOLON; }
","  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "COMMA"); new_node(yytext); return COMMA; }
"="  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "ASSIGN"); new_node(yytext); return ASSIGN; }

"("  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "LPARENTHESIS"); new_node(yytext); return LPARENTHESIS; }
")"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "RPARENTHESIS"); new_node(yytext); return RPARENTHESIS; }
"["  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "LBRACKET"); new_node(yytext); return LBRACKET; }
"]"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "RBRACKET"); new_node(yytext); return RBRACKET; }
"{"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "LBRACE"); new_node(yytext); return LBRACE; }
"}"  { pos_start = pos_end; pos_end += 1; strcpy(token_name, "RBRACE"); new_node(yytext); return RBRACE; }

"//".*  ;
"/*"([^*]|\*+[^*/])*\*+"/" {
     char *p = yytext;
     while (*p) {
          if (*p == '\n') {
               lines++;
          }
          p++;
     }
};

. { printf("非法字符: %c 在行 %d 位置 %d\n", yytext[0], lines, pos_start); exit(1); }

%%
